home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / CM / CMHndOps.c < prev    next >
Encoding:
Text File  |  1996-08-28  |  19.4 KB  |  474 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CMHndOps.c
  3.  
  4.     Contains:    Container Manager Handler Operations
  5.  
  6.     Written by:    Ira L. Ruben
  7.  
  8.     Owned by:    Ed Lai
  9.  
  10.     Copyright:    © 1991 - 1996 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.          <3>     8/13/96    DM        1362809: disable containers on error
  15.          <2>     1/15/96    TJ        Cleaned Up
  16.          <2>     8/26/94    EL        #1181622 Ownership update.
  17.          <1>      2/3/94    EL        first checked in
  18.  
  19.     To Do:
  20. */
  21.  
  22. /*---------------------------------------------------------------------------*
  23.  |                                                                           |
  24.  |                           <<<   CMHndOps.c   >>>                          |
  25.  |                                                                           |
  26.  |                    Container Manager Handler Operations                   |
  27.  |                                                                           |
  28.  |                               Ira L. Ruben                                |
  29.  |                                 12/05/91                                  |
  30.  |                                                                           |
  31.  |                  Copyright Apple Computer, Inc. 1991-1994                 |
  32.  |                           All rights reserved.                            |
  33.  |                                                                           |
  34.  *---------------------------------------------------------------------------*
  35.  
  36.  Containers are always access through handlers, to provide platform independence.  Handlers
  37.  are responsible for doing all the I/O operations, including opening and closing, to
  38.  containers.  They are also responsible for reading and writing the container label.
  39.  
  40.  The routines in this file are the API interfaces to allow the Container Manager to
  41.  determine what handlers it should use for a particular container.  The Container Manager
  42.  handler routines defined here maintain container type name/metahandler associations.
  43.  
  44.  A metahandler is a special required routine the API user defines which is called by the
  45.  API to return the address of the handler I/O routines that the Container Manager needs.
  46.  There following handlers are needed by the API.  They should have these prototypes:    
  47.  
  48.  void open_Handler(CMRefCon refCon, CMOpenMode mode);
  49.  void close_Handler(CMRefCon refCon);
  50.  CMSize flush_Handler(CMRefCon refCon);
  51.  CMSize seek_Handler(CMRefCon refCon, CM_LONG posOff, CMSeekMode mode);
  52.  CMSize tell_Handler(CMRefCon refCon);
  53.  CMSize read_Handler(CMRefCon refCon, CMPtr buffer, CMSize elementSize, CMCount theCount);
  54.  CMSize write_Handler(CMRefCon refCon, CMPtr buffer, CMSize elementSize, CMCount theCount);
  55.  CMEofStatus eof_Handler(CMRefCon refCon);
  56.  CMBoolean trunc_Handler(CMRefCon refCon, CMSize containerSize);
  57.  CMSize containerSize_Handler(CMRefCon refCon);
  58.  void readLabel_Handler(CMRefCon refCon, CMMagicBytes magicByteSequence,
  59.                                                 CMContainerFlags *flags, CM_USHORT *bufSize,
  60.                                                 CM_USHORT *majorVersion, USHORT *minorVersion,
  61.                                                 CMSize *tocOffset, CMSize *tocSize);
  62.  void writeLabel_Handler(CMRefCon refCon, CMMagicBytes magicByteSequence,
  63.                                                  CMContainerFlags flags, CM_USHORT bufSize,
  64.                                                  CM_USHORT majorVersion, USHORT minorVersion,
  65.                                                  CMSize tocOffset, CMSize tocSize);    
  66.  CMValue returnParentValue_Handler(CMRefCon refCon);
  67.  CM_UCHAR *returnContainerName_Handler(CMRefCon refCon);
  68.  CMType returnTargetType_Handler(CMRefCon refCon, CMContainer container);
  69.  void extractData_Handler(CMRefCon refCon, CMDataBuffer buffer, 
  70.                                                      CMSize size, CMPrivateData data);
  71.  void formatData_Handler(CMRefCon refCon, CMDataBuffer buffer, 
  72.                                                   CMSize size, CMPrivateData data);
  73.  
  74.  The names chosen can be, of course, anything.  They were chosen here to document what
  75.  each routine does since the semantics for each routine follow exactly those of standard
  76.  ANSI C.  The last two routines are for reading and writing labels.  See documentation of
  77.  those routines for further details.  Note, we will talk about the "refCon" a little later.
  78.  
  79.  Not all of the above handlers are required at all times.  Some are obviously used only
  80.  for input and others for output.  Here is a chart as to which  routines are required for
  81.  reading, writing, and updating:
  82.  
  83.                                         Mode
  84.                                                      Reading  |  Writing  | Updating
  85.                                                      ---------+-----------+---------
  86.                                 open             X     |     X     |    X
  87.                                 close            X     |     X     |    X
  88.                                 flush                  |           |
  89.                                 seek              X     |     X     |    X
  90.                                 tell              X     |     X     |    X
  91.                                 read               X     |           |    X
  92.                                 write                  |     X     |    X
  93.                                 eof                      |           |
  94.                                 trunc                          |           |
  95.                                 size          X     |     X     |    X
  96.                                 readLabel     X     |           |    X
  97.                                 writeLabel          |     X     |    X
  98.                                 parent              1     |     1     |    
  99.                                 name                |           |     
  100.                                 targetType          |           |    X
  101.                                 extract       X     |     X     |    X
  102.                                 format        X     |     X     |    X
  103.                                                      ---------+-----------+---------
  104.  
  105.  Notes: 1. The parent value handler is required ONLY for embedded container handlers.
  106.                 
  107.  The X's indicate required for the mode.  Blanks mean optional or are not used for the
  108.  mode.  Note, that updating generally is an or'ing of the reading and writing cases.
  109.     
  110.  In each handler routine a "refCon" is passed.  This is short for "reference constant". It
  111.  is an arbitrary (void *) value that is passed to the Container Manager when a container
  112.  is to be opened.  The Container Manager doesn't look at it. It simply passes it on each
  113.  handler call.  The intent is that it will be used as a communication device to allow the
  114.  handler routines to coordinate among themselves.
  115. */
  116.  
  117.  
  118. #include <stddef.h>
  119. #include <string.h>
  120. #include <stdarg.h>
  121. #include <stdio.h>
  122.  
  123. #ifndef __CMVERSION__
  124. #include "CMVers.h"   
  125. #endif
  126. #ifndef __CMTYPES__
  127. #include "CMTypes.h"
  128. #endif
  129. #ifndef __CM_API__
  130. #include "CMAPI.h"
  131. #endif
  132. #ifndef __LISTMGR__
  133. #include "ListMgr.h"
  134. #endif
  135. #ifndef __TOCENTRIES__
  136. #include "TOCEnts.h"   
  137. #endif
  138. #ifndef __TOCOBJECTS__
  139. #include "TOCObjs.h"   
  140. #endif
  141. #ifndef __GLOBALNAMES__
  142. #include "GlbNames.h"   
  143. #endif
  144. #ifndef __CONTAINEROPS__
  145. #include "Containr.h"  
  146. #endif
  147. #ifndef __HANDLERS__
  148. #include "Handlers.h"
  149. #endif
  150. #ifndef __SESSIONDATA__
  151. #include "Session.h"          
  152. #endif
  153. #ifndef __ERRORRPT__
  154. #include "ErrorRpt.h"      
  155. #endif
  156. #ifndef __UTILITYROUTINES__
  157. #include "Utility.h"        
  158. #endif
  159.  
  160.                                                                     CM_CFUNCTIONS
  161.  
  162. /* The following generates a segment directive for Mac only due to 32K Jump Table             */
  163. /* Limitations.  If you don't know what I'm talking about don't worry about it.  The        */
  164. /* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't    */
  165. /* choke compilers that don't recognize them.                                                                                      */
  166.  
  167. #if CM_MPW
  168. #pragma segment CMHandlerOps
  169. #endif
  170.  
  171.  
  172. struct GetOpComArea {                            /* CMGetOperation() object walking comm area layout:    */
  173.     TOCValuePtr      theValue;                /*        the first (should be only) global name value        */
  174.     CM_USHORT             nbrOfGlobalNames;/*        count of nbr of global names found in object        */
  175. };
  176. typedef struct GetOpComArea GetOpComArea, *GetOpComAreaPtr;
  177.  
  178.  
  179. /*-----------------------------------------------------------------------*
  180.  | CMSetMetaHandler - associate a container type name with a metahandler |
  181.  *-----------------------------------------------------------------------*
  182.  
  183.  This routine records the association of type names with their metahandlers. A type name
  184.  is passed to CMOpen[New]Container() so that the Container Manager can use it to call the
  185.  appropriate metahandler to get the actual handler addresses.  Further, a value that has
  186.  a global type name which has an associated metahandler will produce a "dynamic" value.
  187.  
  188.  The function returns the address of the previous metahandler for the specified type if
  189.  one exists.  Otherwise NULL is returned.
  190.  
  191.  Note, that type name/metahandler associations are global to all containers.  Therefore,
  192.  the Container Manager neest to store its information as a function of the current session
  193.  global data defined by CMStartSession().  Hence the sessionData pointer should always be
  194.  the value returned by CMStartSession().
  195. */
  196.  
  197. CMHandlerAddr CM_FIXEDARGS CMSetMetaHandler(CMconst_CMSession sessionData,
  198.                                                                                         CMconst_CMGlobalName typeName,
  199.                                                                                           CMMetaHandler metaHandler)
  200. {
  201.     Boolean                dup;
  202.     CMMetaHandler  prevMetaHandler;
  203.     MetaHandlerPtr h;
  204.     
  205.     if (sessionData == NULL) return (NULL);            /* NOP if not initialized!                                */
  206.     
  207.     /* Enter the new metahandler and its type name into the metaHandler symbol table. The    */
  208.     /* address of the new entry is returned.  If there is one already there, the address     */
  209.     /* of that is returned, dup is set true, and nothing else done.                                                */
  210.     
  211.     h = cmDefineMetaHandler(metaHandler, (CM_UCHAR *)typeName, &dup,
  212.                                                     (SessionGlobalDataPtr)sessionData);
  213.     
  214.     if (!h)    {                                                                        /* if allocation failed...                                */
  215.         SessionERROR1(CM_err_NoHandler, typeName);/* yell and do nothing else                                    */
  216.         return (NULL);                                                        /* ...that's what I said!                                    */
  217.     }
  218.     
  219.     /* If there was a previous entry, update it with the new metahandler address and             */
  220.     /* return the "old" address.                                                                                                                    */
  221.     
  222.     if (dup)    {                                                                    /* if dup entry...                                                */
  223.         prevMetaHandler = h->metaHandler;                    /* ...we will return "old" metahandler        */
  224.         h->metaHandler = metaHandler;                            /* ...just replace with new metahandler        */
  225.     } else
  226.         prevMetaHandler = NULL;                                        /* if not dup, there is no prev. handler    */
  227.     
  228.     return ((CMHandlerAddr)prevMetaHandler);
  229. }
  230.  
  231.  
  232. /*-------------------------------------------------------------------------------*
  233.  | CMGetMetaHandler - return the metahandler address associated with a type name |
  234.  *-------------------------------------------------------------------------------*
  235.  
  236.  This function searches the metaHandler symbol table for the specified typeName and returns
  237.  the associated metahandler address.  NULL is returned if the type name does not exist.
  238.  
  239.  As with CMSetMetaHandler() above, CMGetMetaHandler() requires the session global data
  240.  pointer returned by CMStartSession().
  241. */
  242.  
  243. CMHandlerAddr CM_FIXEDARGS CMGetMetaHandler(CMconst_CMSession sessionData,
  244.                                                                                         CMconst_CMGlobalName typeName)
  245. {
  246.     MetaHandlerPtr h;
  247.     
  248.     if (sessionData == NULL) return (NULL);                            /* NOP if not initialized!                */
  249.  
  250.     h = cmLookupMetaHandler((CM_UCHAR *)typeName, (SessionGlobalDataPtr)sessionData);
  251.     
  252.     if (!((SessionGlobalDataPtr)sessionData)->success) {/* if we had allocation error...    */
  253.         SessionERROR1(CM_err_HandlerError, typeName);            /* ...yell                                                */
  254.         h = NULL;
  255.     }
  256.  
  257.     return (h ? (CMHandlerAddr)h->metaHandler : NULL);    /* NULL or found metahandler            */
  258. }
  259.  
  260.  
  261. /*---------------------------------------------------------*
  262.  | checkValue - check a value to see if it's a global name |
  263.  *---------------------------------------------------------*
  264.  
  265.  This is a cmWalkObject() action routine initiated by CMGetOperation() below to find the
  266.  global name value in an object. The "refCon" is a pointer to a GetOpComArea communication
  267.  area where we will save the value pointer.  We also count the number of global names
  268.  seen in the object.  It shoould be 1.  But we walk the entire object just to be sure.
  269.  
  270.  Note, this "static" is intentionally left to default memory model under DOS since it is
  271.  passed as a function pointer to cmWalkObject().
  272. */
  273.  
  274. static TOCWalkReturns checkValue(ContainerPtr container, TOCValuePtr theValue, CMRefCon refCon)
  275. {
  276.     GetOpComAreaPtr g = (GetOpComAreaPtr)refCon;
  277.     ContainerPtr        unused = container;
  278.     
  279.     if (theValue->flags & kCMGlobalName) {
  280.         g->theValue = theValue;                                                    /* save global name ptr                            */
  281.         ++g->nbrOfGlobalNames;                                                    /* count it too                                            */
  282.     }
  283.     
  284.     return (WalkNextTOCValue);                                                /* continue value walk                            */
  285. }
  286.  
  287.  
  288. /*--------------------------------------------------------------------------*
  289.  | CMGetOperation - get handler for a specific operation on a specific type |
  290.  *--------------------------------------------------------------------------*
  291.  
  292.  This routine takes a targetType which is defined as a globally unique name and uses that
  293.  name find a metahandler. The matahandler, in turn, is used to get the handler routine
  294.  address for the specified operationType.  The function returns the resulting address.
  295.  
  296.  Metahandler proc addresses are given to the Container Manager by calls to
  297.  CMSetMetaHandler().  The global name value for the input targetType is treated as the
  298.  typeName to find the metahandler.  As just mentioned above, the  metahandler is called
  299.  with the operationType to get the operation address returned.
  300. */
  301.  
  302. CMHandlerAddr CM_FIXEDARGS CMGetOperation(CMType targetType,
  303.                                                                                     CMconst_CMGlobalName operationType)
  304. {    
  305.     TOCObjectPtr      theObject;
  306.     TOCValuePtr         theValue;
  307.     ContainerPtr      container;
  308.     CM_CHAR                  *typeName;
  309.     MetaHandlerPtr metaHandler;
  310.     GetOpComArea      getOpComArea;
  311.     
  312.     ExitIfBadType(targetType, NULL);                                    /* validate targetType                            */
  313.  
  314.     theObject = (TOCObjectPtr)targetType;
  315.     container = theObject->container;
  316.         
  317.     /* Walk the entire object and look at all the values to find the value for a global        */
  318.     /* name.  The object can have other properties and values, but there better be only     */
  319.     /* one global name.  The object is walked with cmWalkObject().  The "refCon" we pass    */
  320.     /* is a pointer to a communication area which will hold the count of the global name    */
  321.     /* values and the pointer to it.  As just mentioned, if the count comes back other         */
  322.     /* than 1, we have an error.                                                                                                                    */
  323.     
  324.     getOpComArea.theValue = NULL;                                            /* init value ptr to no value yet        */
  325.     getOpComArea.nbrOfGlobalNames = 0;                                /* there are no global names yet too*/
  326.     
  327.     cmWalkObject(container, theObject, &getOpComArea, NULL, NULL, NULL, checkValue);
  328.     
  329.     /* Get the global name for this type. The type must have only one property, one value,*/
  330.     /* and that value must be for a global name.                                                                                    */
  331.         
  332.     if (getOpComArea.nbrOfGlobalNames > 1) {                    /* must have exactly 1 global name    */
  333.         Container_Disable(container);
  334.         ERROR2(CM_err_AmbiguousType, "CMGetOperation", CONTAINERNAME);
  335.         return (NULL);
  336.     }
  337.  
  338.     if (getOpComArea.nbrOfGlobalNames == 0) {
  339.         Container_Disable(container);
  340.         ERROR2(CM_err_TypeNotGlobal, "CMGetOperation", CONTAINERNAME);
  341.         return (NULL);
  342.     }
  343.     
  344.     /* Set the typeName to point at the global name now that we're happy there is one...    */
  345.     
  346.     theValue = getOpComArea.theValue;
  347.     if (theValue == NULL) return (NULL);                            /* safety                                                        */
  348.     typeName = GetGlobalName(theValue->value.globalName.globalNameSymbol);
  349.     
  350.     /* Use the global name to look up the metahandler in the meta handler symbol table.        */
  351.     /* A few things can go wrong here, but if we successfully found a metahandler symbol    */
  352.     /* table entry we use the resulting metahandler proc pointer to get the routine                */
  353.     /* address for the input operationType.  That's what we return.                                                */
  354.     
  355.     if ((metaHandler = cmLookupMetaHandler((CM_UCHAR *)typeName, SESSION)) == NULL) { 
  356.         Container_Disable(container);
  357.         ERROR1(CM_err_UndefMetaHandler, typeName);
  358.         return (NULL);
  359.     }
  360.     
  361.     if (!SessionSuccess) {                                                        /* if allocation error...                        */
  362.         Container_Disable(container);
  363.         ERROR1(CM_err_HandlerError, typeName);                    /* ...yell                                                    */
  364.         return (NULL);
  365.     }
  366.     
  367.     return ((CMHandlerAddr)(*metaHandler->metaHandler)(NULL, operationType));
  368. }
  369.  
  370.  
  371. /*---------------------------------------------------------------------------*
  372.  | CMMalloc - handler/user interface to Container Manager's memory allocator |
  373.  *---------------------------------------------------------------------------*
  374.  
  375.  This routine provides a access path for the user (usually a handler writer) to use the
  376.  same memory management allocator defined for the current Container Manager session.  size
  377.  bytes are allocated as defined by that handler.  
  378.  
  379.  The session memory allocator handler is defined by the metahandler passed to
  380.  CMStartSession().  The sessionData is the current session refNum returned from
  381.  CMStartSession().
  382. */
  383.  
  384. void CM_PTR * CM_FIXEDARGS CMMalloc(CMSize size, CMSession sessionData)
  385. {
  386.     return ((sessionData == NULL) ? NULL : SessionMalloc(size));
  387. }
  388.  
  389.  
  390. /*---------------------------------------------------------------------------*
  391.  | CMFree - handler/user interface to Container Manager's memory deallocator |
  392.  *---------------------------------------------------------------------------*
  393.  
  394.  This routine provides a access path for the user (usually a handler writer) to use the
  395.  same memory management deallocator defined for the current Container Manager session.  A
  396.  pointer (ptr) assumed to be allocated by CMMalloc() is passed to release the memory in the
  397.  manner defined by the handler.  
  398.  
  399.  The session memory deallocator handler is defined by the metahandler passed to
  400.  CMStartSession().  The sessionData is the current session refNum returned from
  401.  CMStartSession().
  402. */
  403.  
  404. void CM_FIXEDARGS CMFree(CMPtr ptr, CMSession sessionData)
  405. {
  406.     if (sessionData != NULL) SessionFree(ptr);
  407. }
  408.  
  409.  
  410. /*--------------------------------------------------------------------------------*
  411.  | CMError - handler/user interface to Container Manager's session error reporter |
  412.  *--------------------------------------------------------------------------------*
  413.  
  414.  This routines provides an access path for the user (usually an handler writer) to use the
  415.  same error reporter defined for the current Container Manager session.  The session error 
  416.  reporting handler is defined by the metahandler passed to CMStartSession().  The
  417.  sessionData is the current session refNum returned from CMStartSession().  The string is
  418.  the message to be processed by the handler.  Optional string inserts can be passed to put
  419.  into the string.  The string indicates the position of the inserts by "^0", "^1", etc.
  420.  "^0" gets the first insert, "^1" the second, and so on.  Inserts may be repeated.
  421.  
  422.  Note, the maximum length of the passed message plus its inserts is limited to 256 
  423.  characters.  Also, if the error reporting handler returns, so with this routine.
  424. */
  425.  
  426. void CM_VARARGS CMError(CMSession sessionData, CMErrorString message, ...)
  427. {
  428.     va_list inserts;
  429.     
  430.     va_start(inserts, message);
  431.     CMVError(sessionData, message, inserts);
  432.     va_end(inserts);
  433. }
  434.  
  435.  
  436. /*---------------------------------------------------------------------------------*
  437.  | CMVError - handler/user interface to Container Manager's session error reporter |
  438.  *---------------------------------------------------------------------------------*
  439.  
  440.  This routine is the same as CMError() above, except that the extra message inserts are
  441.  given as a variable argument list as defined by the "stdarg" facility.
  442.  
  443.  This routine assumes the caller sets up and terminates the variable arg list using the
  444.  "stdarg.h" calls as follows:
  445.  
  446.              #include <stdarg.h>
  447.             
  448.              callersRoutine(args, ...)
  449.             {
  450.                 va_list inserts;
  451.                 
  452.                 - - -
  453.                 
  454.                 va_start(inserts, args);
  455.                 CMVError(sessionData, message, inserts);
  456.                 va_end(inserts);
  457.                 
  458.                 - - -
  459.             }
  460.             
  461.  See CMError() for further details.
  462. */
  463.  
  464. void CM_FIXEDARGS CMVError(CMSession sessionData, CMErrorString message, va_list inserts)
  465. {
  466.     if (sessionData != NULL) {                                                                        /* if session defined...*/
  467.         strcpy((CM_CHAR *)SessionScratchBufr, message);                                /* ...use private bufr    */
  468.         CMVAddMsgInserts((CM_CHAR *)SessionScratchBufr, 256, inserts);    /* ...add in inserts        */
  469.         SessionERROR1(CM_err_GenericMessage, SessionScratchBufr);        /* ...report error            */
  470.     }
  471. }
  472.                                                           
  473.                                                             CM_END_CFUNCTIONS
  474.